/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

 ****/
package org.activequant.util.scheduling;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Defines a nested SchedulerTimerTask class. Holds the following associated variable:
 * <ul>
 * <li>timer(Timer)</li>
 * </ul>
 * <br>
 *       <b>History:</b><br>
 *       - [11.05.2007] Created (Erik Nijkamp)<br>
 * 
 * @author Erik Nijkamp (based on code by Tom White)
 */
public class Scheduler {
	/**
	 * A TimerTask subclass. Holds the following associated variables:
	 * <ul>
	 * <li>schedulerTask(SchedulerTask)</li>
	 * <li>iterator(ScheduleIterator)</li>
	 * </ul>
	 * @author Dimitar
	 *
	 */
	class SchedulerTimerTask extends TimerTask {
		/**
		 * private SchedulerTask schedulerTask;
		 */
		private SchedulerTask schedulerTask;
		/**
		 * private ScheduleIterator iterator;
		 */
		private ScheduleIterator iterator;
		/**
		 * constructs a SchedulerTimerTask(TimerTask subclass) using the given schedulerTask(SchedulerTask) and iterator(ScheduleIterator) to set its associated
		 * schedulerTask(SchedulerTask) and iterator(ScheduleIterator)
		 * @param schedulerTask
		 * @param iterator
		 */
		public SchedulerTimerTask(SchedulerTask schedulerTask, ScheduleIterator iterator) {
			this.schedulerTask = schedulerTask;
			this.iterator = iterator;
		}
		/**
		 * <strong>1.</strong> invokes <code>schedulerTask.run()</code> on the associated schedulerTask(SchedulerTask).<br/>
		 * <strong>2.</strong> if there is a next Date in the associated iterator(ScheduleIterator) and the state(int) of the associated schedulerTask(SchedulerTask)
		 * is not CANCELLED(2), it schedules the associated timer(Timer) to run the given schedulerTask(SchedulerTask) (wrapped in a SchedulerTimerTask). Otherwise it cancels it.
		 */
		public void run() {
			schedulerTask.run();
			reschedule(schedulerTask, iterator);
		}
	}
	/**
	 * private final Timer timer = new Timer();
	 */
	private final Timer timer = new Timer();
	/**
	 * an empty Scheduler constructor
	 */
	public Scheduler() {
	}
	/**
	 * invokes <code>timer.cancel()</code> on the associated timer(Timer)
	 */
	public void cancel() {
		timer.cancel();
	}
	/**
	 * if there is a next Date in the given iterator(ScheduleIterator) and the state(int) of the given schedulerTask(SchedulerTask)
	 * is not VIRGIN(0), it schedules the associated timer(Timer) to run the given schedulerTask(SchedulerTask) (wrapped in a SchedulerTimerTask) and
	 * sets its state(int) to SCHEDULED(1). Otherwise it cancels it.
	 * @param schedulerTask
	 * @param iterator
	 */
	public void schedule(SchedulerTask schedulerTask, ScheduleIterator iterator) {

		Date time = iterator.next();
		if (time == null) {
			schedulerTask.cancel();
		} else {
			synchronized (schedulerTask.lock) {
				if (schedulerTask.state != SchedulerTask.VIRGIN) {
					throw new IllegalStateException("Task already scheduled " + "or cancelled");
				}
				schedulerTask.state = SchedulerTask.SCHEDULED;
				schedulerTask.timerTask = new SchedulerTimerTask(schedulerTask, iterator);
				timer.schedule(schedulerTask.timerTask, time);
			}
		}
	}
	/**
	 * if there is a next Date in the given iterator(ScheduleIterator) and the state(int) of the given schedulerTask(SchedulerTask)
	 * is not CANCELLED(2), it schedules the associated timer(Timer) to run the given schedulerTask(SchedulerTask) (wrapped in a SchedulerTimerTask). Otherwise it cancels it.
	 * @param schedulerTask
	 * @param iterator
	 */
	private void reschedule(SchedulerTask schedulerTask, ScheduleIterator iterator) {

		Date time = iterator.next();
		if (time == null) {
			schedulerTask.cancel();
		} else {
			synchronized (schedulerTask.lock) {
				if (schedulerTask.state != SchedulerTask.CANCELLED) {
					schedulerTask.timerTask = new SchedulerTimerTask(schedulerTask, iterator);
					timer.schedule(schedulerTask.timerTask, time);
				}
			}
		}
	}

}
